Vue.js 官网 结论的一处的错误 一、前言
为什么说是对Vue.js官网一处结论描述错误的探究呢?主要是在学习 Composition API 的 setup()
函数发现官网有一段这样的模式
When
setup is executed, the component instance has not been created yet. As a result, you will only be able to access the following properties:
其含义就是:执行 setup
时,组件实例尚未被创建。因此,你只能访问以下 property,下图就是官方对此的描述,真实情况如其所说吗?
二、验证这个错误 正所谓了解真相,方能自由。探索这个问题的对错必须依赖 Vue3源码
在整个源码中核心文件: runtime-core
、 runtime-dom
、 compiler-core
、 runtime-dom
几个文件
进入到 runtime-core 文件夹
打开 renderer.ts
文件
我们可以从544行中的这段代码开始一步步分析
2.1 处理组件节点,调用 processComponent
1 2 3 4 5 6 7 8 9 10 11 12 13 14 } else if (shapeFlag & ShapeFlags.COMPONENT) { processComponent( n1, n2, container, anchor, parentComponent, parentSuspense, isSVG, slotScopeIds, optimized ) }
这里我们来看看 processComponent
的实现中很明显 已经创建了 instance
这么个实例, 接着在1335行中开始调用 setupComponent(instance)
将 上面创建的 instance
传递了出去
2.2 组件挂载,调用 mountComponent
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 const mountComponent: MountComponentFn = ( initialVNode, container, anchor, parentComponent, parentSuspense, isSVG, optimized ) => { const compatMountInstance = __COMPAT__ && initialVNode.component const instance: ComponentInternalInstance = compatMountInstance || (initialVNode.component = createComponentInstance( initialVNode, parentComponent, parentSuspense ))
2.2 开始处理 setupComponent
该函数在 component.ts
中进行了处理,那么它又是如何处理呢?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 ) => { const compatMountInstance = __COMPAT__ && initialVNode.component const instance: ComponentInternalInstance = compatMountInstance ||(initialVNode.component = createComponentInstance( initialVNode, parentComponent, parentSuspense )) if (__DEV__ && instance.type.__hmrId) { registerHMR(instance) } if (__DEV__) { pushWarningContext(initialVNode) startMeasure(instance, `mount` ) } if (isKeepAlive(initialVNode)) { ;(instance.ctx as KeepAliveContext).renderer = internals } if (!(__COMPAT__ && compatMountInstance)) { if (__DEV__) { startMeasure(instance, `init` ) } setupComponent(instance) if (__DEV__) { endMeasure(instance, `init` ) } }
调转到它的实现文件中,我们可以看到这样一段代码实现,在这个函数中处理几件事情
调用 setupStatefulComponent
初始化有状态的组件
初始化 props
、 slots
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 export function setupComponent ( instance: ComponentInternalInstance, isSSR = false ) { isInSSRComponentSetup = isSSR const { props, children } = instance.vnode const isStateful = isStatefulComponent(instance) initProps(instance, props, isStateful, isSSR) initSlots(instance, children) const setupResult = isStateful ? setupStatefulComponent(instance, isSSR) : undefined isInSSRComponentSetup = false return setupResult }
2.3 提取 setup
函数 在这里通过 const { setup } = Component
拿到 该函数,看到这段代码也就能得出一个结论
如果实现了 setup函数,那么通过vue2 options api 是不会生效的
vue3是兼容 vue2 options api
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 const { setup } = Componentif (setup) { const setupContext = (instance.setupContext = setup.length > 1 ? createSetupContext(instance) : null ) currentInstance = instance pauseTracking() const setupResult = callWithErrorHandling( setup, instance, ErrorCodes.SETUP_FUNCTION, [__DEV__ ? shallowReadonly(instance.props) : instance.props, setupContext] ) resetTracking() currentInstance = null if (isPromise(setupResult)) { if (isSSR) { return setupResult .then((resolvedResult: unknown ) => { handleSetupResult(instance, resolvedResult, isSSR) }) .catch(e => { handleError(e, instance, ErrorCodes.SETUP_FUNCTION) }) } else if (__FEATURE_SUSPENSE__) { instance.asyncDep = setupResult } else if (__DEV__) { warn( `setup() returned a Promise, but the version of Vue you are using ` + `does not support it yet.` ) } } else { handleSetupResult(instance, setupResult, isSSR) } } else { finishComponentSetup(instance, isSSR) }
2.4 统一执行 callWithErrorHandling
函数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 export function callWithErrorHandling ( fn: Function , instance: ComponentInternalInstance | null , type: ErrorTypes, args?: unknown[] ) { let res try { res = args ? fn(...args) : fn() } catch (err) { handleError(err, instance, type) } return res }
这个函数其实本质就是自己封装了一个 try catch ,在其内部来来调 fn
三、结论
结合源码一分析,就很确定 执行 setup
时,组件实例 已经创建
,官方描述是有问题的~